import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Random;


/**
 * Pretends to be a LinkSPOT and sends random data to the server
 * @author David A. Boyuka, II
 */
public class LinkSPOTStub {
	private static final String REMOTE_SERVER_ADDRESS = "localhost";
	private static final int REMOTE_SERVER_PORT = 4545;

	private Socket remoteServerSocket;
	private DataOutputStream remoteServerSink;

	private Random rand = new Random();
	
	public LinkSPOTStub(byte[] sensorIDs, long delayBetweenPackets) {
		if (!setUpRemoteServerConnection()) {
			System.exit(1);
		}
		System.out.println("Connected to remote server");
		
		doFakeStuff(sensorIDs, delayBetweenPackets);
	}
	
	private boolean setUpRemoteServerConnection() {
		
		try {
			remoteServerSocket = new Socket(REMOTE_SERVER_ADDRESS, REMOTE_SERVER_PORT);
			remoteServerSink = new DataOutputStream(remoteServerSocket.getOutputStream());
			return true;
		} catch (IOException ioe) {
			ioe.printStackTrace();
			closeConnections();
			return false;
		}
	}
	
	private void closeConnections() {
		try {
			if (remoteServerSink != null) remoteServerSink.close();
		} catch (IOException ioe) {}

		try {
			if (remoteServerSocket != null) remoteServerSink.close();
		} catch (IOException ioe) {}
	}
	
	

	private void doFakeStuff(byte[] sensorIDs, long delayBetweenPackets) {
		try {
			for (int i = 0; ; i = (i+1)%sensorIDs.length) {
				sendFakeSamplePacket(sensorIDs[i]);
				System.out.println("Send fake packet from sensorID " + sensorIDs[i]);

				try { Thread.sleep(delayBetweenPackets); } catch (InterruptedException ie) {}
			}
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	private void sendFakeSamplePacket(byte sensorID) throws IOException {
		// Calculation of number of readings:
		// * Packet = MAC (1B) + Timestamp (8B) + Reading (2B)
		//          + Delta (2B) + Reading (2B) + ...
		//
		// * Packet size = 1 + 8 + 2 + (readings-1)*(2+2) = 11 + (readings-1)*4
		//               = 7 + readings*4
		// * readings = ((packet size) - 7)/4
		// 
		// Yay!
		//
		// Note: assumes that the number of samples in a packet is less than 127
		//

		// Calculate the number of samples in the datagram, and write this value to the remote server
		byte numSamplesLeft = 15;

		remoteServerSink.writeByte(numSamplesLeft);
		remoteServerSink.writeByte(sensorID);

		// Continually write the last sample read, and read a new one, until there are none left
		while (numSamplesLeft > 0) {
			remoteServerSink.writeLong(System.currentTimeMillis() - 1000L*numSamplesLeft);
			remoteServerSink.writeShort(rand.nextInt(1<<16));
			numSamplesLeft--;
		}
	}
	
	public static void main(String[] args) throws Exception {
		long delay = 1000L;
		byte[] sensorIDs = {0};
		if (args.length > 0) {
			delay = Long.parseLong(args[0]);
			if (args.length > 1) {
				sensorIDs = new byte[args.length - 1];
				for (int i = 0; i < sensorIDs.length; i++) sensorIDs[i] = (byte)Integer.parseInt(args[i+1]);
			}
		}
		
		LinkSPOTStub stub = new LinkSPOTStub(sensorIDs, delay);
	}
}
